import java.io.*;
import java.net.Socket;
import java.util.Vector;


public class newServer implements Runnable{
	private Socket clientSocket = null;
	public DataInputStream in = null;
	public DataOutputStream out = null;
	private String message = null;
	private myRouter router = null;
	
	/**
	 * Constructor. Since this class implements Runnable this is normally
	 * used like Thread server = new Thread(new Server(1111)). 
	 * @param listeningOn The port this server listens on for connections.
	 */
	public newServer(Socket client, myRouter mr){
		this.clientSocket = client;
		this.router = mr;
	}
	
	/**
	 * Another extension of the Runnable interface. When the created server
	 * thread calls server.start() this function is called in addition to
	 * allocating other Thread specific resources.
	 */
	public void run() {
		System.out.println("Server: " + Thread.currentThread());
		
		try {
			try{
				this.initiateStreams();
				this.establishConnection();
				
				while (true) {
					listenTables();
					
					try { Thread.sleep(50); } catch (InterruptedException e) {e.printStackTrace();}
				}
			}catch (EOFException e){
				System.err.println("Terminated");
			}
		}
		catch(IOException e){
			e.printStackTrace();
		}
	}
	
	public void listenTables() {
		Vector<String> tempTable = new Vector<String>();
		String tmp;
		try {
			this.in.readUTF();
			tmp = this.in.readUTF();
			
			while (!tmp.equals("DONE")) {
				tempTable.add(tmp);
				tmp = this.in.readUTF();
			}
		} catch (IOException e) {e.printStackTrace();}
		//System.out.println("this is the tmp table: " + tempTable);
		String[] info;
		// skip the first index, its the id part 
		for (int i=1; i<tempTable.size(); ++i) {
			info = tempTable.get(i).split("-");
			info[1] = ""+(Integer.parseInt(info[1]) + 1);
			tmp = info[0] + "-" + info[1] + "-" + info[2];
			
			tempTable.set(i, tmp);
		}
		
		router.syncTable(tempTable);
	}
	
	/**
	 * Get the input and output streams from the newly created socket.
	 * @throws IOException
	 */
	public void initiateStreams() throws IOException{
		this.out = new DataOutputStream(this.clientSocket.getOutputStream());
		this.in = new DataInputStream(this.clientSocket.getInputStream());
		
		if (this.in == null || this.out == null) this.initiateStreams();
		else { this.out.flush(); }
	}
	
	/**
	 * Make sure we can actually send data between the routers.
	 * We do this by trying to send data repeatedly, and the
	 * first time an error doesn't occur we assume we have a connection.
	 */
	public void establishConnection(){
		boolean once =false;
		do{
			try {
				this.out.writeUTF("Connected!");
				router.has_a_connection = true;
				once = true;
				this.message = this.listen();
				System.err.println("message from client: " + this.message);
			}
			catch (IOException e) {
				e.printStackTrace();
			}
		}
		while(this.message != "TERMINATE" && once ==false);
	}
	
	/**
	 * Helper method so we can send data from the interface.
	 * @param msg What we want to send to another router.
	 */
	public void send(String mesg) {
		try {
			this.out.writeUTF(mesg);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Helper method so we can receive data from the interface.
	 * We first check if there is more than one byte to read.
	 * @return msg What was read, if anything, from another router. Otherwise null.
	 */
	public String listen() {
		String msg = null;
		if (this.in != null) {
			try {
				if (this.in.available() > 0) {
					msg = this.in.readUTF();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return msg;
	}

	/**
	 * Clean up all the open sockets and streams so that they don't
	 * remain open after the application exits.
	 */
	public void closeConnection() {
		try {
			if (this.out != null) {
				this.out.writeUTF("TERMINATE");
				this.out.flush();
				this.out.close();
			}
			if (this.in != null) this.in.close();
			if (this.clientSocket != null) this.clientSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}